package com.qfedu.aunt.commons.auth.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qfedu.aunt.commons.auth.entity.SecurityUser;
import com.qfedu.aunt.commons.auth.security.TokenManager;
import com.qfedu.aunt.commons.manager.RedisManager;
import com.qfedu.aunt.commons.result.R;
import com.qfedu.aunt.commons.result.ResponseCode;
import com.qfedu.aunt.commons.utils.ResponseUtils;
import com.qfedu.aunt.commons.utils.UserInfoContainer;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

/**
 * 用户登陆的这个过滤器
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private TokenManager tokenManager;
    private AuthenticationManager authenticationManager;

    private RedisManager redisManager;


    public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisManager redisManager) {
        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.redisManager=redisManager;
        this.setPostOnly(false);
        //这个就是前端请求的时候要登陆的地址 随便写的
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/user/login","POST"));
    }

    //1 获取表单提交用户名和密码
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

           //获取表单提交数据(这个用户名和密码是前端提供的)
//            String username = request.getParameter("username");
//            String password = request.getParameter("password");
           //这里需要获取传递过来的这个JSON格式的数据  JSON格式的数据 只能使用POST 放到请求实体中(HTTP协议)
        ServletInputStream in= null;
        try {
            in = request.getInputStream();
            byte[] buf=new byte[1024];
            int length = in.read(buf);
            //接下来：转换成字符串
            String data = new String(buf, 0, length);
            //将JSON格式的字符串转换成 JSON对象
            JSONObject jsonObject = JSON.parseObject(data);
            if(null!=jsonObject){
                String username = (String) jsonObject.get("username");
                String password = (String) jsonObject.get("password");
                return authenticationManager.authenticate(
                        new UsernamePasswordAuthenticationToken(username,password,
                    new ArrayList<>()));
            }
            //执行到这里 说明没有接受到数据
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 这个方法是用户登陆成功之后的回调方法
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, 
                                            HttpServletResponse response, FilterChain chain, Authentication authResult)
            throws IOException, ServletException {
        //认证成功，得到认证成功之后用户信息
        SecurityUser user = (SecurityUser)authResult.getPrincipal();
        //根据用户名生成token
        String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername(),user.getCurrentUserInfo().getUserId());
        //这里将权限信息写入到本地的HashMap中 方便获取
       // UserInfoContainer.add(token,user.getPermissionValueList());
        //这里需要放到Redis中进行持久化

        redisManager.addString(token,JSON.toJSONString(user.getPermissionValueList()),30, TimeUnit.DAYS);

        //返回token
        ResponseUtils.out(response, R.ok().setData("token",token).setData("username",user.getUsername()));
    }

    //3 认证失败调用的方法
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {
        ResponseUtils.out(response,R.error(
                ResponseCode.USERNAME_PASSWORD_EXCEPTION.getCode(),
                ResponseCode.USERNAME_PASSWORD_EXCEPTION.getMessage()));
    }
}
